package org.epsi.blokus.server;

import java.util.Observable;
import java.util.Observer;
import java.util.Random;
import org.epsi.blokus.commun.Message;

/**
 * Gestion propre à un salon
 * @author julien.lafont
 */
public class Salon implements Observer {

    public ServerClient maitre;
    private ServerClient invite;
    private int index;
    private String nomSalon;
    private int nombreJoueurs;

    public Salon(ServerClient source, Integer index, String nom) {
        this.index = index;
        this.maitre = source;
        this.invite = null;
        this.nomSalon = nom;
        this.nombreJoueurs = 1;
    }

    /**
     * Transmission des serveurs
     * @param o
     * @param arg
     */
    public void update(Observable o, Object message) {
        Message mess = (Message)message;
        ServerClient source = (ServerClient)o;

        switch(mess.getTypeMessage())
        {
            case infos_adversaires:
                envoyerMessageAdversaire(mess, source);
            break;

            case nous_sommes_pret:

                // Qui commence ? Choix aléatoire
                Random rand = new Random(System.currentTimeMillis());
                ServerClient[] joueurs = { this.invite, this.maitre };
                int nb = rand.nextInt(2);

                // Envoie des messages pour signaler les tours de jeux initiaux
                joueurs[nb].envoyerMessage(new Message(Message.TTypeMessage.a_toi_de_jouer));
                System.out.println("Message1 ok");
                joueurs[(nb+1)%2].envoyerMessage(new Message(Message.TTypeMessage.en_attente));
                System.out.println("Message2 ok");
                
            break;

            case chat_ingame_poster:
                String txt = (String)mess.getObject("MESSAGE");
                System.out.println("Chat à retransmettre : "+txt);
                
                Message rep = new Message(Message.TTypeMessage.chat_ingame_recevoir)
                        .addObject("MESSAGE", (String)txt);
                
                envoyerMessageAdversaire(rep, source);
            break;

            case poser_pion:

                System.out.println("Poser pion");
                // C'est au tour de l'adversaire
                Message repPoserPion = new Message(Message.TTypeMessage.a_toi_de_jouer)
                            .addObject("LIG", mess.getObject("LIG"))
                             .addObject("COL", mess.getObject("COL"));

                envoyerMessageAdversaire(repPoserPion, source);
                System.out.println("Message à l'adversaire envoyé");

                // Le joueur courant attend
                source.envoyerMessage(new Message(Message.TTypeMessage.en_attente));
                System.out.println("Message à la source envoyé");
            break;

            case timeout:
                envoyerMessageAdversaire(new Message(Message.TTypeMessage.gagnant), source);
            break;

            case gagnant:
                envoyerMessageAdversaire(new Message(Message.TTypeMessage.perdant), source);
            break;
        }

    }

    /**
     * Un invité entre sur le salon
     * @param sc
     */
    public void ajouterInvite(ServerClient sc)
    {
        this.invite = sc;
        this.nombreJoueurs++;
    }

    /**
     * Retire le client du serveur (maitre ou invité)
     * @param sc CLient
     * @return Vrai si le client était le maitre du serveur
     */
    public Boolean retirerClient(ServerClient sc)
    {
        // Retirer le maitre ?
        if (sc!=null && sc.equals(this.maitre))
        {
            fermer();
            return true;
        }
        
        // Retirer un invite ?
        else
        {
            this.invite = null;
            this.nombreJoueurs = 1 ;
            return false;
        }
        
    }

    /**
     * Fermer le salon
     */
    public void fermer()
    {

        // On retire l'invité si il y en avait un
        if (this.invite != null)
        {
            this.invite.setSalon(null);
            this.invite.envoyerMessage(new Message(Message.TTypeMessage.salon_fermeture_prematuree));
        }

        // ACK sur la fermeture de salon pour le maitre
        this.maitre.envoyerMessage(new Message(Message.TTypeMessage.fermeture_salon_ack));
        
        this.maitre = null;
        this.nombreJoueurs = 0 ;
        this.invite = null;
    }


    /**
     * Envoyer un message au maitre
     * @param m
     */
    public void envoyerMessageMaitre(Message m) {
        this.maitre.envoyerMessage(m);
    }

    /**
     * Envoyer un message à l'invité
     * @param m
     */
    public void envoyerMessageInvite(Message m) {
        invite.envoyerMessage(m);
    }

    /**
     * Envoie un message à l'adversaire du client source
     * @param m
     * @param source
     */
    public void envoyerMessageAdversaire(Message m, ServerClient source)
    {

        if (source.equals(maitre))  envoyerMessageInvite(m);
        else                        envoyerMessageMaitre(m);
       
    }

    /**
     * La partie commence, on en informe le ou les invités
     */
    void lancerPartie() {

        envoyerMessageInvite(new Message(Message.TTypeMessage.lancer_partie));
        this.invite.deleteObservers();
        this.maitre.deleteObservers();
        this.invite.addObserver(this); // Les messages sont directements observés par le salon
        this.maitre.addObserver(this);
    }



    public int getIndex()
    {
        return index;
    }


    @Override
    public String toString()
    {
        return this.index + " " +this.nomSalon + " par  Client "+ this.maitre.getNumero();
    }

    
    public ServerClient getMaitre()
    {
        return maitre;
    }


    public ServerClient getInvite()
    {
        return maitre;
    }


    public int getNbJoueurs()
    {
        return this.nombreJoueurs;
    }

    
    public String getNom()
    {
        return this.nomSalon;
    }




}
